package com.iotechn.unimall.app.api.distribution;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.iotechn.unimall.biz.service.config.ConfigBizService;
import com.iotechn.unimall.biz.service.distribution.DistributionBizService;
import com.iotechn.unimall.core.exception.AppServiceException;
import com.iotechn.unimall.core.exception.ExceptionDefinition;
import com.iotechn.unimall.core.exception.ServiceException;
import com.iotechn.unimall.data.domain.DistributionBalanceDetailDO;
import com.iotechn.unimall.data.domain.DistributionDO;
import com.iotechn.unimall.data.domain.DistributionWithdrawDO;
import com.iotechn.unimall.data.domain.WithdrawalOperLogDO;
import com.iotechn.unimall.data.dto.DistributionDTO;
import com.iotechn.unimall.data.dto.DistributionOrderDTO;
import com.iotechn.unimall.data.dto.DistributionUserDTO;
import com.iotechn.unimall.data.enums.DistributionWithdrawStatusType;
import com.iotechn.unimall.data.enums.StatusType;
import com.iotechn.unimall.data.mapper.DistributionBalanceDetailMapper;
import com.iotechn.unimall.data.mapper.DistributionMapper;
import com.iotechn.unimall.data.mapper.DistributionWithdrawMapper;
import com.iotechn.unimall.data.mapper.WithdrawalOperLogMapper;
import com.iotechn.unimall.data.model.Page;
import org.apache.ibatis.session.RowBounds;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: rize
 * Date: 2019/11/29
 * Time: 12:22
 */
@Service
public class DistributionServiceImpl implements DistributionService {

    @Autowired
    private DistributionMapper distributionMapper;

    @Autowired
    private DistributionBalanceDetailMapper distributionBalanceDetailMapper;

    @Autowired
    private DistributionWithdrawMapper distributionWithdrawMapper;
    @Autowired
    private WithdrawalOperLogMapper withdrawalOperLogMapper;

    @Autowired
    private ConfigBizService configBizService;

    @Autowired
    private DistributionBizService distributionBizService;

    @Value("${com.iotechn.unimall.wx.mini.app-id}")
    private String wxMiNiAppid;

    @Value("${com.iotechn.unimall.wx.app.app-id}")
    private String wxAppAppid;

    private static final Logger logger = LoggerFactory.getLogger(DistributionServiceImpl.class);

    @Override
    public DistributionDTO info(Long userId) throws ServiceException {
        List<DistributionDO> list = distributionMapper.selectList(
                new EntityWrapper<DistributionDO>()
                        .eq("user_id", userId));
        if (CollectionUtils.isEmpty(list)) {
            throw new AppServiceException(ExceptionDefinition.DISTRIBUTION_USER_NOT_EXIST);
        }
        DistributionDTO distributionDTO = new DistributionDTO();
        BeanUtils.copyProperties(list.get(0), distributionDTO);
        Integer integer = distributionWithdrawMapper.sumWithdraw(list.get(0).getId());
        if (integer == null) {
            integer = 0;
        }
        distributionDTO.setTotalWithdraw(integer);
        return distributionDTO;
    }

    @Override
    public String create(Long distributionId, String phone, String realname, Long userId) throws ServiceException {
        DistributionDO parentDO = distributionMapper.selectById(distributionId);
        if (parentDO == null) {
            throw new AppServiceException(ExceptionDefinition.DISTRIBUTION_USER_NOT_EXIST);
        }
        Integer count = distributionMapper.selectCount(new EntityWrapper<DistributionDO>().eq("user_id", userId));
        if (count > 0) {
            throw new AppServiceException(ExceptionDefinition.DISTRIBUTION_YOU_ARE_DISTRIBUTION_USER);
        }
        if (parentDO.getLevel() > 2) {
            throw new AppServiceException(ExceptionDefinition.DISTRIBUTION_LEVEL_THREE_CANNOT_CREATE_DISTRIBUTOR);
        }
        Date now = new Date();
        DistributionDO distributionDO = new DistributionDO();
        distributionDO.setParentId(parentDO.getId());
        distributionDO.setStatus(StatusType.ACTIVE.getCode());
        distributionDO.setBalance(0);
        distributionDO.setFreezeBalance(0);
        distributionDO.setRealname(realname);
        distributionDO.setPhone(phone);
        distributionDO.setUserId(userId);
        distributionDO.setGmtUpdate(now);
        distributionDO.setGmtCreate(now);
        distributionDO.setAllowChild(1);
        distributionDO.setLevel(parentDO.getLevel() + 1);
        if (distributionMapper.insert(distributionDO) > 0) {
            return "ok";
        }
        throw new AppServiceException(ExceptionDefinition.APP_UNKNOWN_EXCEPTION);
    }

    @Override
    public Page<DistributionBalanceDetailDO> balanceDetail(Integer pageNo, Integer pageSize, Integer type, Long userId) throws ServiceException {
        List<DistributionDO> list = distributionMapper.selectList(
                new EntityWrapper<DistributionDO>()
                        .eq("user_id", userId));
        if (CollectionUtils.isEmpty(list)) {
            throw new AppServiceException(ExceptionDefinition.DISTRIBUTION_USER_NOT_EXIST);
        }
        Wrapper<DistributionBalanceDetailDO> wrapper = new EntityWrapper<DistributionBalanceDetailDO>();
        wrapper.eq("distribution_id", list.get(0).getId());
        wrapper.orderBy("id", false);
        if (type != null) {
            if (1 == type) {
                wrapper.ne("balance_delta", 0);
            } else if (2 == type) {
                wrapper.ne("freeze_balance_delta", 0);
            }
        }
        List<DistributionBalanceDetailDO> detailDOS = distributionBalanceDetailMapper.selectPage(new RowBounds((pageNo - 1) * pageSize, pageSize), wrapper);
        Integer count = distributionBalanceDetailMapper.selectCount(wrapper);
        return new Page<>(detailDOS, pageNo, pageSize, count);
    }

    @Override
    public Page<DistributionWithdrawDO> withdrawDetail(Integer pageNo, Integer pageSize, Long userId) throws ServiceException {
        List<DistributionDO> list = distributionMapper.selectList(
                new EntityWrapper<DistributionDO>()
                        .eq("user_id", userId));
        if (CollectionUtils.isEmpty(list)) {
            throw new AppServiceException(ExceptionDefinition.DISTRIBUTION_USER_NOT_EXIST);
        }
        Wrapper<DistributionWithdrawDO> wrapper = new EntityWrapper<>();
        wrapper.eq("distribution_id", list.get(0).getId());
        wrapper.orderBy("id", false);
        List<DistributionWithdrawDO> withdrawDOS = distributionWithdrawMapper.selectPage(new RowBounds((pageNo - 1) * pageSize, pageSize), wrapper);
        Integer count = distributionWithdrawMapper.selectCount(wrapper);
        return new Page<>(withdrawDOS, pageNo, pageSize, count);
    }

    @Override
    public String getQRCode(Long userId) throws ServiceException {
        return getCommonsCode(userId, 0);
    }

    private String getCommonsCode(Long userId, int type) throws ServiceException {
        List<DistributionDO> list = distributionMapper.selectList(
                new EntityWrapper<DistributionDO>()
                        .eq("user_id", userId));
        if (CollectionUtils.isEmpty(list)) {
            //throw new AppServiceException(ExceptionDefinition.DISTRIBUTION_USER_NOT_EXIST);
            // 若用户不存在分销。则立即创建该用户
            Date now = new Date();
            DistributionDO distributionDO = new DistributionDO();
            distributionDO.setParentId(0l);
            distributionDO.setStatus(StatusType.ACTIVE.getCode());
            distributionDO.setBalance(0);
            distributionDO.setFreezeBalance(0);
            distributionDO.setUserId(userId);
            distributionDO.setGmtUpdate(now);
            distributionDO.setGmtCreate(now);
            distributionDO.setAllowChild(1);
            distributionDO.setLevel(1);
            if (distributionMapper.insert(distributionDO) > 0) {
                list.add(distributionDO);
            }
        }
        //使用懒加载
        DistributionDO distributionDO = list.get(0);
        if (type == 0) {
            if (!StringUtils.isEmpty(distributionDO.getQrUrl())) {
                return distributionDO.getQrUrl();
            }
        } else {
            if (!StringUtils.isEmpty(distributionDO.getSubordinateQrUrl())) {
                return distributionDO.getSubordinateQrUrl();
            }
        }
        String url = configBizService.generateWxMiniCode((type == 0 ? "pages/index/index?distribution=" : "pages/distribution/create?distribution=") + distributionDO.getId());
        DistributionDO updateDistributionDO = new DistributionDO();
        updateDistributionDO.setId(distributionDO.getId());
        if (type == 0) {
            updateDistributionDO.setQrUrl(url);
        } else {
            updateDistributionDO.setSubordinateQrUrl(url);
        }
        updateDistributionDO.setGmtUpdate(new Date());
        if (distributionMapper.updateById(updateDistributionDO) > 0) {
            return url;
        }
        throw new AppServiceException(ExceptionDefinition.APP_UNKNOWN_EXCEPTION);
    }

    @Override
    public String getSubQRCode(Long userId) throws ServiceException {
        return getCommonsCode(userId, 1);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String withdraw(String ip, Integer sum, Long distributionId, Long userId) throws ServiceException {
        //锁定两张表
        DistributionDO distributionDO = distributionMapper.selectByIdForUpdate(distributionId);
        //校验是是否tradeNo
        int hours = Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd" + (hours > 12 ? "01" : "02"));
        String tradeNo = sdf.format(new Date()) + distributionId;
        Integer count = distributionWithdrawMapper.selectCount(new EntityWrapper<DistributionWithdrawDO>().eq("trade_no", tradeNo));
        if (count > 0) {
            throw new AppServiceException(ExceptionDefinition.DISTRIBUTION_YOU_CAN_ONLY_WITHDRAW_ONCE_EACH_DAY);
        }
        if (!distributionDO.getUserId().equals(userId)) {
            throw new AppServiceException(ExceptionDefinition.APP_UNKNOWN_EXCEPTION);
        }
        //校验余额是否充足
        if (distributionDO.getBalance() < sum) {
            throw new AppServiceException(ExceptionDefinition.DISTRIBUTION_BALANCE_NOT_ENOUGH);
        }
        /*DistributionBalanceDetailDO lastDetail = distributionBalanceDetailMapper.getDistributionUserLastForUpdate(distributionDO.getId());
        //判断两个数据是否一致
        if (!lastDetail.getFreezeBalance().equals(distributionDO.getFreezeBalance()) || !lastDetail.getBalance().equals(distributionDO.getBalance())) {
            throw new AppServiceException(ExceptionDefinition.DISTRIBUTION_YOUR_DATA_NOT_CONSTANCY);
        }*/
        //提现申请 先将钱减掉 发申请
        distributionDO.setBalance(distributionDO.getBalance() - sum);
        distributionMapper.updateById(distributionDO);
        Date now = new Date();
        DistributionWithdrawDO withdrawDO = new DistributionWithdrawDO();
        withdrawDO.setSum(sum);
        withdrawDO.setDistributionId(distributionId);
        withdrawDO.setGmtUpdate(now);
        withdrawDO.setGmtCreate(now);
        withdrawDO.setTradeNo(tradeNo);
        withdrawDO.setUserId(userId);
        //withdrawDO.setShopId(SessionUtil.getUser().getUserShopDO().getId());
        //withdrawDO.setShopName(SessionUtil.getUser().getUserShopDO().getShopName());
        withdrawDO.setStatus(DistributionWithdrawStatusType.WAIT_AUDIT.getCode());
        distributionWithdrawMapper.insert(withdrawDO);
        //记录
        WithdrawalOperLogDO log = new WithdrawalOperLogDO();
        log.setGmtCreate(now);
        log.setGmtUpdate(now);
        log.setStatus(DistributionWithdrawStatusType.WAIT_AUDIT.getCode());
        log.setApplyId(withdrawDO.getId());
        log.setDrawMoney(withdrawDO.getSum().longValue());
        log.setOperUserId(userId);
        log.setOperTime(now);
        withdrawalOperLogMapper.insert(log);

        return "ok";
    }

    @Override
    public Integer balance(Long userId) throws ServiceException {
        Integer balance = distributionMapper.selectBalanceByUserId(userId);
        if (balance == null) {
            return 0;
        }
        return balance;
    }

    @Override
    public Page<DistributionOrderDTO> getOrderPage(Integer pageNo, Integer pageSize, Long userId) throws ServiceException {
        List<DistributionDO> list = distributionMapper.selectList(
                new EntityWrapper<DistributionDO>()
                        .eq("user_id", userId));
        if (CollectionUtils.isEmpty(list)) {
            throw new AppServiceException(ExceptionDefinition.DISTRIBUTION_USER_NOT_EXIST);
        }
        DistributionDO distributionDO = list.get(0);
        return distributionBizService.getDistributionOrderPage(pageNo, pageSize, distributionDO.getId());
    }

    @Override
    public List<DistributionUserDTO> getUserList(Long userId) throws ServiceException {
        List<DistributionDO> list = distributionMapper.selectList(
                new EntityWrapper<DistributionDO>()
                        .eq("user_id", userId));
        if (CollectionUtils.isEmpty(list)) {
            throw new AppServiceException(ExceptionDefinition.DISTRIBUTION_USER_NOT_EXIST);
        }
        DistributionDO distributionDO = list.get(0);
        return distributionBizService.getDistributionUserPage(distributionDO.getId());
    }


}
